/*************************************************************
   Copyright(C) 2017 by WuIslet
   All rights reserved.
   
   FindInPrefab.cs
   UnityFramework
   
   Created by WuIslet on 2018-02-01.
   
*************************************************************/
#if !USE_ILRUNTIME

using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;

using UnityEngine;
using UnityEngine.SceneManagement;

public partial class FindInPrefab
{
    // 1. 查找范围 SearchRangeClass
    private enum SearchRange
    {
        查找文件夹,
        查找文件,
        当前场景,
        指定GUID使用yaml查找,
        读取文件, //TODO 1. 纯净文件名, 2. json, 3. 本程序的输出文件, 4. 直接拿Editor.log进行分析
    }
    private static SearchRange mSearchRange;
    private static Dictionary<SearchRange, Phase<Func<FindResult, bool>, List<FindResult>>> SearchRangeClass;

    private static void ResetSearchRange()
    {
        SearchRangeClass = new Dictionary<SearchRange, Phase<Func<FindResult, bool>, List<FindResult>>>
            {
                {SearchRange.查找文件夹, new SearchExplorerFolder()},
                {SearchRange.查找文件, new SearchFile()},
                {SearchRange.当前场景, new SearchScene()},
                {SearchRange.指定GUID使用yaml查找, new SearchWithGuid()},
                {SearchRange.读取文件, new SearchWithTextFile()},
            };
    }

    #region class 查找文件夹
    class SearchExplorerFolder : Phase<Func<FindResult, bool>, List<FindResult>>
    {
        private string[] example = new[] { FIND_TYPE_GAMEOBJECT, FIND_TYPE_OBJECT, "animatorcontroller", "UISkinDataBase", "UISkinSpriteData", "spriteatlas"};
        string mFindPath = ROOT_PATH;
        string mExtension = FIND_TYPE_GAMEOBJECT;
        override public List<FindResult> FuncReturn(Func<FindResult, bool> input)
        {
            var list = new List<FindResult>();
            if (string.IsNullOrEmpty(mExtension))
                mExtension = FIND_TYPE_OBJECT;
            var filterString = "t:" + mExtension;
            string[] searchGuids = AssetDatabase.FindAssets(filterString, new[] { mFindPath });
            foreach (string guid in searchGuids)
            {
                //EditorUtility.DisplayProgressBar("Fix Missing prefab", filePath, (index + 0f) / (len + 0f));
                //TODO 增加进度条在每个阶段。
                var path = AssetDatabase.GUIDToAssetPath(guid);
                var obj = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(path);

                var find = new FindResult
                {
                    type = mExtension,
                    rawObj = obj,
                    go = obj as GameObject,
                    name = obj.name,
                    path = path,
                };
                if (input == null || input(find))
                {
                    list.Add(find);
                }
            }
            return list;
        }

        override public void OnDraw()
        {
            mFindPath = EditorToolsUtils.DrawDragBrowserFolderPath("    文件夹：", mFindPath, "", "");

            EditorGUILayout.BeginHorizontal();
            GUILayout.Label("后缀：", GUILayout.MaxWidth(30));
            mExtension = EditorGUILayout.TextField(mExtension, GUILayout.MaxWidth(80));
            foreach (var key in example)
            {
                if (GUILayout.Button(key, GUILayout.MaxWidth(120)))
                {
                    mExtension = key;
                }
            }
            EditorGUILayout.EndHorizontal();
        }

        override public string CheckNeed(bool isSave, SearchRange sr, bool isDS, HitRule hr, AfterDeal ad)
        {
            if (string.IsNullOrEmpty(mFindPath))
            {
                return "请输入文件夹路径";
            }
            return "";
        }

        public void SetPath(string path)
        {
            mFindPath = path;
        }
    }
    #endregion class 查找文件夹

    #region class 查找文件
    class SearchFile : Phase<Func<FindResult, bool>, List<FindResult>>
    {
        private bool isSel = false;
        string mFindPath = ROOT_PATH;
        public UnityEngine.Object mTarget;
        private string targetPath;
        private string targetGUID;
        private string Extension;
        override public List<FindResult> FuncReturn(Func<FindResult, bool> input)
        {
            var list = new List<FindResult>();
            if (mTarget != null)
            {
                var find = new FindResult
                {
                    type = Extension,
                    rawObj = mTarget,
                    go = mTarget as GameObject,
                    name = mTarget.name,
                    path = AssetDatabase.GetAssetPath(mTarget),
                };
                if (input == null || input(find))
                {
                    list.Add(find);
                }
            }
            return list;
        }

        override public void OnDraw()
        {
            isSel = GUILayout.Toggle(isSel, "使用选中", GUILayout.MaxWidth(100));
            if (isSel)
            {
                SetTarget(Selection.activeObject);
                EditorToolsUtils.DrawClickCopyLabel("    文件：", mTarget == null ? "无选中" : mFindPath, parent: window);
            }
            else
            {
                mFindPath = EditorToolsUtils.DrawDragBrowserFolderPath("    文件：", mFindPath, "", "object");
                mTarget = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(mFindPath);
            }

            EditorToolsUtils.DrawClickCopyLabel("    名字：", mTarget == null ? "无选中" : mTarget.name, parent: window);
            targetPath = AssetDatabase.GetAssetPath(mTarget);
            targetGUID = AssetDatabase.AssetPathToGUID(targetPath);
            EditorToolsUtils.DrawClickCopyLabel("    GUID：", mTarget == null ? "无选中" : targetGUID, parent: window);
            if (mTarget == null)
            {
                Extension = "";
            }
            else
            {
                Extension = GetTypeWithExtension(Path.GetExtension(targetPath));
            }
        }

        override public string CheckNeed(bool isSave, SearchRange sr, bool isDS, HitRule hr, AfterDeal ad)
        {
            if (mTarget == null)
            {
                return "请输入文件";
            }
            return "";
        }

        public void SetTarget(UnityEngine.Object target, bool clearSel = false)
        {
            if (clearSel)
                isSel = false;
            mTarget = target;
            mFindPath = AssetDatabase.GetAssetPath(target);
        }

        public void SetExtension(string ext)
        {
            Extension = ext;
        }
    }
    #endregion class 查找文件

    #region class 当前场景
    private class SearchScene : Phase<Func<FindResult, bool>, List<FindResult>>
    {
        override public List<FindResult> FuncReturn(Func<FindResult, bool> input)
        {
            var list = new List<FindResult>();
            var stage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();
            if (stage != null)
            {
                var find = new FindResult
                {
                    type = FIND_TYPE_GAMEOBJECT,
                    rawObj = stage.prefabContentsRoot,
                    go = stage.prefabContentsRoot,
                    name = stage.prefabContentsRoot.name,
                    path = stage.assetPath,
                };
                if (input == null || input(find))
                {
                    list.Add(find);
                }
            }
            else
            {
                var scene = SceneManager.GetActiveScene();
                foreach (GameObject pObject in scene.GetRootGameObjects())
                {
                    if (pObject.transform.parent != null)
                    {
                        continue;
                    }

                    if (pObject.hideFlags == HideFlags.NotEditable || pObject.hideFlags == HideFlags.HideAndDontSave)
                    {
                        continue;
                    }

                    if (Application.isEditor)
                    {
                        string sAssetPath = AssetDatabase.GetAssetPath(pObject.transform.root.gameObject);
                        if (!string.IsNullOrEmpty(sAssetPath))
                        {
                            continue;
                        }
                    }

                    var find = new FindResult
                    {
                        type = FIND_TYPE_GAMEOBJECT,
                        rawObj = pObject,
                        go = pObject,
                        name = pObject.name,
                        path = pObject.name,
                    };
                    if (input == null || input(find))
                    {
                        list.Add(find);
                    }
                }
            }
            return list;
        }

        override public void OnDraw()
        {
            GUILayout.Label("根节点列表：");
            var stage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();
            if (stage != null)
            {
                GUILayout.Label(stage.prefabContentsRoot.name);
            }
            else
            {
                var scene = SceneManager.GetActiveScene();
                foreach (GameObject pObject in scene.GetRootGameObjects())
                {
                    if (pObject.transform.parent != null)
                    {
                        continue;
                    }

                    if (pObject.hideFlags == HideFlags.NotEditable || pObject.hideFlags == HideFlags.HideAndDontSave)
                    {
                        continue;
                    }

                    if (Application.isEditor)
                    {
                        string sAssetPath = AssetDatabase.GetAssetPath(pObject.transform.root.gameObject);
                        if (!string.IsNullOrEmpty(sAssetPath))
                        {
                            continue;
                        }
                    }
                    GUILayout.Label(pObject.name);
                }
            }
        }
    }
    #endregion class 当前场景

    #region class 指定GUID使用yaml查找
    class SearchWithGuid : Phase<Func<FindResult, bool>, List<FindResult>>
    {
        private bool isSel = false;
        public UnityEngine.Object mTarget;
        private string targetKeyword;

        private bool isCustomString;
        private bool isReg;
        private bool isWord;
        private string customString;
        override public List<FindResult> FuncReturn(Func<FindResult, bool> input)
        {
            string keyword;
            if (isCustomString)
                keyword = string.Format("\"{0}\"", customString);
            else
                keyword = targetKeyword;

            var references = SearchWithRG(keyword, isReg, isWord);
            var list = new List<FindResult>();
            for (int i = 0, len = references.Count; i < len; ++i)
            {
                var file = references[i];
                string assetPath = file;
                if (file.EndsWith(".meta"))
                {
                    assetPath = file.Substring(0, file.Length - ".meta".Length);
                }

                var obj = AssetDatabase.LoadMainAssetAtPath(assetPath);
                if (obj != null)
                {
                    var find = new FindResult
                    {
                        type = FIND_TYPE_OBJECT,
                        rawObj = obj,
                        go = obj as GameObject,
                        name = obj.name,
                        path = assetPath,
                    };
                    if (input == null || input(find))
                    {
                        list.Add(find);
                    }
                }
            }
            return list;
        }

        override public void OnDraw()
        {
            isCustomString = GUILayout.Toggle(isCustomString, "是否查找customString？");
            if (isCustomString)
            {
                customString = EditorGUILayout.TextField("    customString：", customString);
                isReg = GUILayout.Toggle(isReg, "正则查找");
                isWord = GUILayout.Toggle(isWord, "全字匹配");
            }
            else
            {
                isReg = false;
                isWord = false;

                isSel = GUILayout.Toggle(isSel, "使用选中", GUILayout.MaxWidth(100));
                if (isSel)
                {
                    mTarget = Selection.activeObject;
                }
                else
                {
                    mTarget = EditorGUILayout.ObjectField(mTarget, typeof(UnityEngine.Object), false);
                }

                targetKeyword = EditorToolsUtils.DrawObjectDetail(mTarget, window);
            }
        }
    }
    #endregion class 指定GUID使用yaml查找

    #region class 读取文件
    class SearchWithTextFile : Phase<Func<FindResult, bool>, List<FindResult>>
    {
        private string searchRange = ROOT_PATH;
        private string filePath = "";
        override public List<FindResult> FuncReturn(Func<FindResult, bool> input)
        {
            var list = new List<FindResult>();

            var prefabNameList = new List<string>();
            using (FileStream fs = new FileStream(filePath, FileMode.Open))
            {
                var sr = new StreamReader(fs);
                while (sr.Peek() != -1)
                {
                    prefabNameList.Add(sr.ReadLine().Trim());
                }
                sr.Close();
            }

            for (int i = 0; i < prefabNameList.Count; ++i)
            {
                var prefabName = prefabNameList[i];
                var path = Path.Combine(searchRange, prefabName + ".prefab");
                GameObject go = AssetDatabase.LoadAssetAtPath<GameObject>(path);
                if (go == null)
                    continue;

                var find = new FindResult
                {
                    type = FIND_TYPE_OBJECT,
                    rawObj = go,
                    go = go,
                    name = go.name,
                    path = path,
                };
                if (input == null || input(find))
                {
                    list.Add(find);
                }
            }
            return list;
        }

        override public void OnDraw()
        {
            searchRange = EditorGUILayout.TextField("基础路径：", searchRange);
            filePath = EditorToolsUtils.DrawDragBrowserFolderPath("    文件：", filePath, "", "txt");
        }

        override public string CheckNeed(bool isSave, SearchRange sr, bool isDS, HitRule hr, AfterDeal ad)
        {
            if (string.IsNullOrEmpty(filePath))
            {
                return "请输入文件路径";
            }
            return "";
        }
    }
    #endregion class 读取文件

    private bool DrawSearchRange()
    {
        bool isOK = true;
        var dragRect = EditorGUILayout.BeginVertical("Box");
        mSearchRange = (SearchRange)EditorGUILayout.EnumPopup("查找范围：", mSearchRange, GUILayout.MinWidth(100));
        if (SearchRangeClass != null && SearchRangeClass.ContainsKey(mSearchRange))
        {
            var cls = SearchRangeClass[mSearchRange];
            var error = cls.CheckNeed(mIsSavePrefab, mSearchRange, mIsDeepSearch, mHitRule, mAfterDeal);
            if (!string.IsNullOrEmpty(error))
            {
                isOK = false;
                EditorGUILayout.HelpBox(error, MessageType.Error);
            }
            cls.OnDraw();
        }

        EditorGUILayout.EndVertical();

        if (Event.current.type == EventType.DragUpdated && dragRect.Contains(Event.current.mousePosition))
        {
            if (DragAndDrop.objectReferences.Length == 1) //只有一个的时候
            {
                DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
                Event.current.Use();
            }
        }
        else if (Event.current.type == EventType.DragPerform && dragRect.Contains(Event.current.mousePosition))
        {
            if (DragAndDrop.objectReferences.Length == 1) //只有一个的时候
            {
                var sel = DragAndDrop.objectReferences[0];
                var path = AssetDatabase.GetAssetPath(sel);
                if (sel is DefaultAsset && !string.IsNullOrEmpty(path) && !Path.HasExtension(path))
                {
                    mSearchRange = SearchRange.查找文件夹;
                    var cls = SearchRangeClass[mSearchRange] as SearchExplorerFolder;
                    cls.SetPath(path);
                }
                else
                {
                    mSearchRange = SearchRange.查找文件;
                    var cls = SearchRangeClass[mSearchRange] as SearchFile;
                    cls.SetTarget(sel, true);
                }
            }
        }

        return isOK;
    }
}

#endif